﻿using System;
using System.Linq;
using System.Web;
using System.Web.Configuration;
using System.Web.Mvc;
using System.Data.Linq;
using SacNetUG.Areas.Forum.Models;
using SacNetUG.Areas.Forum.Models.Abstract;
using SacNetUG.Areas.Forum.Models.Concrete;

namespace SacNetUG.Areas.Forum.Controllers
{
    public class PostsController : Controller
     {
        private IPostsRepository postsRepository;
        public PostsController()
        {
            try
            {
                string connString = WebConfigurationManager.ConnectionStrings["SacNetUGConnectionString"].ToString();
                postsRepository = new SqlPostsRepository (connString);
            }
            catch   //(Exception ex) any exception should be recorded in a log file available to the moderator
            {
            }
        }

        public ActionResult Home()
        {
            return RedirectToAction("ListOfSubjects");
        }

        public ViewResult ListOfSubjects()
        {
            //This method presents a listing of the subjects (a condensation of the full question/topic) 
            //available for discussion in this technical forum.  Each subject is an 'ActiveLink' which, 
            //when clicked, leads to the complete post statement and resulting posts to this subject;   
            //(see SubjectAndResultingPosts() method)
            ViewData["AllSubjects"] = "All Subjects for discussion or answers";

            try
            {
                string connString = WebConfigurationManager.ConnectionStrings["SacNetUGConnectionString"].ToString();
                DataContext postsContext = new DataContext(connString);

                var allSubjects = (from p in postsContext.GetTable<Post>()
                                   where p.IsTheInitialPost == true && p.Flagged == false
                                   orderby p.DatePosted descending
                                   select p).ToList();

                return View(allSubjects);
            }
            catch   //(Exception ex) any exception should be recorded in a log file available to the moderator
            {
                return View();
            }
        }

        //[Authorize]
        [HttpGet]
        public ViewResult CreateNewSubject()
        {
            //This method presents a form for an authenticated user to create a new subject for discussion.
            return View("CreateNewSubject", new Post());
        }

        //[Authorize]
        [HttpPost]
        public ActionResult CreateNewSubject(Post newSubjectPost) 
        {
            //This 'Post' version of the 'CreateNewSubject' method receives the input data for the new subject
            //from the form, stores in in the database, and returns the user to the 'ListOfSubjects'.  The user 
            //is presented a message in red indicating the successful submittal.  This message is presented via 
            //the 'TempData[]' dictionary, and is therefore deleted by the system after a single presentation.
            try
            {
                string post = Request.Form["ThePost"];
                newSubjectPost.ThePost = post;     
                string subject = Request.Form["InitialPostSubject"];
                if ((subject == null) || (subject == ""))
                {
                    subject = post.Substring(0, 80);
                }
                newSubjectPost.InitialPostSubject = subject;
                string postorHandle = Request.Form["PostorHandle"];
                if ((postorHandle == "") || (postorHandle == null))
                {
                    newSubjectPost.PostorHandle = "anon";
                }
                else
                {
                    newSubjectPost.PostorHandle = postorHandle;
                }
                newSubjectPost.IsTheInitialPost = true;
                newSubjectPost.DatePosted = (DateTime.Now).ToShortDateString();
                newSubjectPost.PostedTo = 0;
                newSubjectPost.NumberOfPosts = 0;
                newSubjectPost.Flagged = false;
                newSubjectPost.FlaggedThenApproved = false;

                if (ModelState.IsValid)
                {
                    postsRepository.SaveSummary(newSubjectPost);
                    TempData["SaveNewSubject"] = "Your new Subject has been saved";
                    return RedirectToAction("ListOfSubjects");
                }
                else //there is a validation error;  send user back to form fields with error in entry messages;  hmmmm!  correct?
                {
                    return View();
                }
            }
            catch   //(Exception ex) any exception should be recorded in a log file available to the moderator
            {
                return View();
            }
        }
        
        public ActionResult SubjectAndResultingPosts()
        {
            //This method generates a listing of a selected subject (from the 'ListOfSubjects()' method).
            //The listing includes the condensed subject, the full post, and all of the responses/posts 
            //to date to this subject.  
            ViewData["SubjectAndResultingPosts"] = "Selected Subject with Responses";

            try
            {
                string connString = WebConfigurationManager.ConnectionStrings["SacNetUGConnectionString"].ToString();
                DataContext postsContext = new DataContext(connString);

                int postedTo = 0;
                Post selectedPost = new Post();

                if (!(Request.QueryString["postedto"] == null))         //user clicked a link in ListOfSubjects to get here
                {                                                       //or user was returned here after adding a Post to this subject
                    //retrieve selected PostID from ActionLink() in ListOfSubjects, or from RedirectToAction() in 'CreateNewPostToASubject'
                    postedTo = int.Parse(Request.QueryString["postedto"]); 
                }
                else
	            {
                    return RedirectToAction("ListOfSubjects");          //make user start over?  will that solve it?
	            }

                //retrieve the post object that user had selected in 'ListOfSubjects'
                //'postedTo' is a misleading term here;  it is the post id of the subject
                selectedPost = postsRepository.Posts.First(p => p.PostID == postedTo);
                int numberOfPosts = selectedPost.NumberOfPosts;

                //retrieve into ViewData[ ] the selected subject's Properties;  
                ViewData["postedto"] = postedTo;
                ViewData["numberofposts"] = numberOfPosts;
                ViewData["selectedsubject"] = selectedPost.InitialPostSubject;
                ViewData["postorhandle"] = selectedPost.PostorHandle;
                ViewData["dateofpost"] = selectedPost.DatePosted;
                ViewData["thepost"] = selectedPost.ThePost;
                ViewData["postid"] = selectedPost.PostID;

                if (numberOfPosts == 0)
                {
                    return View("NoResultingPosts");
                }
                else
                {
                    //  the variable 'postedTo' is the same value in all posts to the selected subject
                    var selectedPostsData = (from p in postsContext.GetTable<Post>()
                                             where p.PostedTo == postedTo && p.Flagged == false
                                             orderby p.DatePosted ascending
                                             select p).ToList();

                    return View(selectedPostsData);
                }
            }
            catch   //(Exception ex) any exception should be recorded in a log file available to the moderator
            {
                return View();
            }
        }

        //[Authorize]
        [HttpGet]
        public ViewResult CreateNewPostToASubject()
        {
            //This method (requires authentication) presents a form to the user for entering a new post 
            //to a selected subject.
            try
            {
                int postedTo = int.Parse(Request.QueryString["postedto"]);      //retrieve the 'postedto' parameter passed in

                Post selectedPost = new Post();             //retrieve the post object that user had selected from db
                selectedPost = postsRepository.Posts.First(p => p.PostID == postedTo);

                Post newPost = new Post();
                newPost.PostedTo = postedTo;    //besides being needed in the new post, this value will be used in the [HttpPost] version
                ViewData["selectedsubject"] = selectedPost.InitialPostSubject;  //this one we need for this related view
                ViewData["postorhandle"] = selectedPost.PostorHandle;
                ViewData["dateofpost"] = selectedPost.DatePosted;
                ViewData["thepost"] = selectedPost.ThePost;

                return View("CreateNewPostToASubject", newPost);
            }
            catch   //(Exception ex) any exception should be recorded in a log file available to the moderator
            {
                return View();
            }
        }

        //[Authorize]
        [HttpPost]
        public ActionResult CreateNewPostToASubject(Post newPostToTheSubject)
        {
            //This method receives data from a form for creating a new post to an existing subject.
            //The new post is saved to the database, the number of posts to the selected subject is 
            //incremented, and the user is returned to the 'SubjectAndResultingPosts()' listing.
            //A message informs the user that the post has been saved, and the new post is shown
            //in the refreshed listing.  This message is presented via the 'TempData[]' dictionary,
            //and is therefore deleted by the system after a single presentation.
            try
            {
                newPostToTheSubject.ThePost = Request.Form["ThePost"];
                string postorHandle = Request.Form["PostorHandle"];
                if ((postorHandle == "") || (postorHandle == null))     //no entry by user
                {
                    newPostToTheSubject.PostorHandle = "anon";
                }
                else
                {
                    newPostToTheSubject.PostorHandle = postorHandle;
                }
                newPostToTheSubject.IsTheInitialPost = false;
                newPostToTheSubject.DatePosted = (DateTime.Now).ToShortDateString();
                newPostToTheSubject.InitialPostSubject = "";
                newPostToTheSubject.Flagged = false;
                newPostToTheSubject.FlaggedThenApproved = false;

                if (ModelState.IsValid)
                {
                    postsRepository.CreateNewPostToASubject(newPostToTheSubject);          //add this new post to the database

                    //  make the change in NumberOfPosts the last thing
                    int selectedPostID = newPostToTheSubject.PostedTo;

                    Post selectedPost = new Post();             //retrieve the post object that user had selected from db
                    selectedPost = postsRepository.Posts.First(p => p.PostID == selectedPostID);
                    int numberOfPosts = selectedPost.NumberOfPosts;
                   
                    IncrementAndStoreNumberOfPosts(selectedPostID, numberOfPosts, 1);   //increment NumberOfPosts in db for subject

                    //  send user to see his or her added post to the subject
                    TempData["SaveNewPost"] = "Your new Post has been saved";
                    return RedirectToAction("SubjectAndResultingPosts", new { postedto = selectedPostID });
                }
                else //there is a validation error;  send user back to form fields with error in entry messages
                {
                    return View();
                }
            }
            catch
            {
                return View();
            }
        }

        private void IncrementAndStoreNumberOfPosts(int postIDOfSubject, int numberOfPosts, int numberToIncrement)
        { 
            //This method increments a field in the database which stores the number of posts to a subject. 
            //This method is called from the method 'CreateNewPostToASubject()'.
            try
            {
                int postIDToEdit = postIDOfSubject;
                var postToEdit = postsRepository.Posts.First(p => p.PostID == postIDToEdit);

                postToEdit.NumberOfPosts = numberOfPosts + numberToIncrement;

                if (ModelState.IsValid)
                {
                    postsRepository.IncrementNumberOfPosts(postToEdit);
                }
            }
            catch   //(Exception ex) any exception should be recorded in a log file;  that is all that can be done at this point
            {
            }
        }

        //[Authorize]
        public ActionResult FlagPostToASubject()
        {
            //This method results from an authenticated user 'flagging' a post for some reason for approval from the Moderator.
            //A boolean/bit field in the database is set to indicate the post has been flagged, and is thereby not shown until
            //the post has been approved by the moderator (or deleted).  The Moderator has access to a report of all flagged 
            //posts, and can therein approve or delete each post depending on his/her judgement.  If a Moderator approves an
            //item after having been flagged, that item may not be flagged again.  A message informs the user that the flag  
            //has been recorded, and that the post will not be shown until/unless approved by the Moderator.  This message is 
            //presented via the 'TempData[]' dictionary, and is therefore deleted by the system after a single presentation.
            try
            {
                int postID = int.Parse(Request.QueryString["postid"]);      //user clicked 'Flag' in ListOfSubjects to get here

                //set the db field 'Flagged' equal to true for this subject
                var postToEdit = postsRepository.Posts.First(p => p.PostID == postID);
                if (postToEdit.FlaggedThenApproved == false)
                {
                    postToEdit.Flagged = true;
                    if (ModelState.IsValid)
                    {
                        postsRepository.FlagSelectedSubjectOrPost(postToEdit);
                        TempData["SaveFlaggedPost"] = "The item you just 'flagged' has been removed from the listing until reviewed by the Moderator";
                        return RedirectToAction("SubjectAndResultingPosts", new { postedto = postToEdit.PostedTo });
                    }
                    else    //some error happened;  perhaps this should be a nested try/catch block, and record any error in a log file
                    {
                        return RedirectToAction("ListOfSubjects");    //else, if an error, redirecting to here is a bit like 'rebooting'
                    }
                }
                else //(postToEdit.FlaggedThenApproved == true)
                {
                    TempData["SaveFlaggedPost"] = "User: the item you just 'flagged' was previously 'flagged', and then approved by the forum moderator";
                    return RedirectToAction("SubjectAndResultingPosts", new { postedto = postToEdit.PostedTo });   //incorrect;  postID refers to the post user tried to flag;  we need to pass in the subject's postID 
                }
            }
            catch   //(Exception ex) any exception should be recorded in a log file available to the moderator
            {
                return View();
            }
        }

        //[Authorize]
        public ActionResult FlagSubject()
        {
            //This method results from an authenticated user 'flagging' a subject for some reason for approval from the Moderator.
            //A boolean/bit field in the database is set to indicate the item has been flagged, and is thereby not shown until
            //the subject has been approved by the moderator (or deleted).  The Moderator has access to a report of all flagged 
            //items, and can therein approve or delete each depending on the Moderator's judgement.  If a Moderator approves an
            //item after having been flagged, that item may not be flagged again.  A message informs the user that the flag  
            //has been recorded, and that the subject will not be shown until/unless approved by the Moderator.  This message is 
            //presented via the 'TempData[]' dictionary, and is therefore deleted by the system after a single presentation.
            try
            {
                int postID = int.Parse(Request.QueryString["postID"]);      //user clicked 'Flag' in ListOfSubjects to get here

                //set the db field 'Flagged' equal to true for this subject
                var postToEdit = postsRepository.Posts.First(p => p.PostID == postID);
                if (postToEdit.FlaggedThenApproved == false)
                {
                    postToEdit.Flagged = true;
                    if (ModelState.IsValid)
                    {
                        postsRepository.FlagSelectedSubjectOrPost(postToEdit);
                        TempData["SaveFlaggedSubject"] = "Your 'flagged' subject has been removed from the list for consideration by the Moderator";
                        return RedirectToAction("ListOfSubjects");
                    }
                    else    //some error happened;  maybe a nested try/catch should be used here, eh?
                    {
                        return RedirectToAction("ListOfSubjects");    //is this where we would want to return?;  message probably shouldn't be shown to user 
                    }
                }
                else //(postToEdit.FlaggedThenApproved == true)
                {
                    TempData["SaveFlaggedSubject"] = "This Subject was previously 'flagged', and approved by the forum Moderator";
                    return RedirectToAction("ListOfSubjects"); 
                }
            }
            catch   //(Exception ex) any exception should be recorded in a log file available to the moderator
            {
                return View();
            }
        }

        public ViewResult Guidelines()
        {
            //This method presents a few elementary statements about the policies of this technical forum.
            return View();
        }

    }
}